import 'package:device_calendar/device_calendar.dart';
import 'package:photo_frame/user/user_manager.dart';
import 'package:photo_frame/utils/a_logger.dart';
import 'package:photo_frame/utils/calendar_helper.dart';
import 'package:rrule/rrule.dart' as rruleUtil;

class EventDTO {
  int? autoId;
  int? id;
  String? frame_id;
  String? event_id;
  String? accountType;
  String? accountName;
  String? calendarDisplayName;

  String? title;
  int? allDay;
  int? dtstart;
  int? dtend;
  String? rrule;
  String? reminder;
  String? eventTimezone;
  String? eventLocation;
  String? description;
  String? attendees;
  num? etag;
  int? finish;

  /// 1 已同步
  int? sync;

  /// 0 新增 1 更新 2 删除
  int? action;

  List<String> get memberList =>
      attendees?.split(",") ?? [UserManager.instance.getId().toString()];

  //本地字段
  ///完成时间戳集合
  Set<num>? timestamp;

  //每天是否完成状态
  int? todayFinish = 0;


  EventDTO(
      {this.autoId,
      this.id,
      this.frame_id,
      this.event_id,
      this.accountType,
      this.accountName,
      this.calendarDisplayName,
      this.title,
      this.allDay,
      this.dtstart,
      this.dtend,
      this.rrule,
      this.reminder,
      this.eventTimezone,
      this.eventLocation,
      this.description,
      this.attendees,
      this.etag,
      this.finish = 0,
      this.sync = 1,
      this.action = 0,
      this.todayFinish = 0,
      });

  factory EventDTO.fromJson(Map<String, dynamic> json) {
    return EventDTO(
      autoId: json['autoId'] as int?,
      id: json['id'] as int?,
      frame_id: json['frame_id'] as String?,
      event_id: (json['event_id'] is int)
          ? json['event_id'].toString()
          : json['event_id'] as String?,
      accountType: json['accountType'] as String?,
      accountName: json['accountName'] as String?,
      calendarDisplayName: json['calendarDisplayName'] as String?,
      title: json['title'] as String?,
      allDay: json['allDay'] as int?,
      dtstart: json['dtstart'] as int?,
      dtend: json['dtend'] as int?,
      rrule: json['rrule'] as String?,
      reminder: json['reminder'] as String?,
      eventTimezone: json['eventTimezone'] as String?,
      eventLocation: json['eventLocation'] as String?,
      description: json['description'] as String?,
      attendees: (json['attendees'] is List<dynamic>)
          ? (json['attendees'] as List<dynamic>).join(",")
          : json['attendees'] as String?,
      etag: json['etag'] as num?,
      finish: json['finish'] as int?,
      sync: json['sync'] as int?,
      action: json['action'] as int?,
    );
  }

  factory EventDTO.buildFromSystem(String frameId, Calendar calendar, Event e) {
    var ruleStr = parseRecurrenceRule(e)?.toString();
    return EventDTO(
        frame_id: frameId,
        event_id: e.eventId ?? "",
        accountType: calendar.accountType,
        accountName: calendar.accountName,
        calendarDisplayName: calendar.name,
        title: e.title,
        allDay: e.allDay == true ? 1 : 0,
        dtstart: e.start?.millisecondsSinceEpoch,
        dtend: e.end?.millisecondsSinceEpoch,
        rrule: ruleStr?.isNotEmpty == true
            ? ruleStr!.substring("RRULE:".length, ruleStr.length)
            : null,
        reminder: e.reminders?.where((e) => e.minutes != null).join(","),
        eventTimezone: e.end?.location.name,
        eventLocation: e.location,
        description: e.description,
        attendees: "${UserManager.instance.getId() ?? ""}",
        etag: DateTime.now().millisecondsSinceEpoch);
  }

  EventDTO copyWithMap({
    int? autoId,
    int? id,
    String? frame_id,
    String? event_id,
    String? accountType,
    String? accountName,
    String? calendarDisplayName,
    String? title,
    int? allDay,
    int? dtstart,
    int? dtend,
    String? rrule,
    String? reminder,
    String? eventTimezone,
    String? eventLocation,
    String? description,
    String? attendees,
    num? etag,
    int? finish,
    int? sync,
    int? action,
    int? todayFinish,
  }) {
    return EventDTO(
      autoId: autoId ?? this.autoId,
      id: id ?? this.id,
      frame_id: frame_id ?? this.frame_id,
      event_id: event_id ?? this.event_id,
      accountType: accountType ?? this.accountType ?? "",
      accountName: accountName ?? this.accountName ?? "",
      calendarDisplayName:
          calendarDisplayName ?? this.calendarDisplayName ?? "",
      title: title ?? this.title ?? "",
      allDay: allDay ?? this.allDay,
      dtstart: dtstart ?? this.dtstart,
      dtend: dtend ?? this.dtend,
      rrule: rrule ?? this.rrule,
      reminder: reminder ?? this.reminder ?? "",
      eventTimezone: eventTimezone ?? this.eventTimezone ?? "",
      eventLocation: eventLocation ?? this.eventLocation ?? "",
      description: description ?? this.description ?? "",
      attendees: attendees ?? this.attendees ?? "",
      etag: etag ?? this.etag,
      finish: finish ?? this.finish,
      sync: sync ?? this.sync,
      action: action ?? this.action,
      todayFinish: todayFinish ?? this.todayFinish,
    );
  }

  void updateWith(EventDTO other) {
    if (other.autoId != null) autoId = other.autoId;
    if (other.id != null) id = other.id;
    if (other.frame_id != null) frame_id = other.frame_id;
    if (other.event_id != null) event_id = other.event_id;
    if (other.accountType != null) accountType = other.accountType;
    if (other.accountName != null) accountName = other.accountName;
    if (other.calendarDisplayName != null)
      calendarDisplayName = other.calendarDisplayName;
    if (other.title != null) title = other.title;
    if (other.allDay != null) allDay = other.allDay;
    if (other.dtstart != null) dtstart = other.dtstart;
    if (other.dtend != null) dtend = other.dtend;
    if (other.rrule != null) rrule = other.rrule;
    if (other.reminder != null) reminder = other.reminder;
    if (other.eventTimezone != null) eventTimezone = other.eventTimezone;
    if (other.eventLocation != null) eventLocation = other.eventLocation;
    if (other.description != null) description = other.description;
    if (other.attendees != null) attendees = other.attendees;
    if (other.etag != null) etag = other.etag;
    if (other.finish != null) finish = other.finish;
    if (other.sync != null) sync = other.sync;
    if (other.action != null) action = other.action;
  }

  Map<String, dynamic> toMap() {
    return {
      'autoId': autoId,
      'id': id,
      'frame_id': frame_id,
      'event_id': event_id,
      'accountType': accountType,
      'accountName': accountName,
      'calendarDisplayName': calendarDisplayName,
      'title': title,
      'allDay': allDay,
      'dtstart': dtstart,
      'dtend': dtend,
      'rrule': rrule,
      'reminder': reminder,
      'eventTimezone': eventTimezone,
      'eventLocation': eventLocation,
      'description': description,
      'attendees': attendees,
      'etag': etag,
      'finish': finish,
      'sync': sync,
      'action': action,
    };
  }

  RecurrenceRule? toRecurrenceRule() {
    //Unsupported value for RRULE part WKST: "SU" (Only MO is supported.)
    // ALogger.i("toRecurrenceRule enter : rrule=$rrule");
    if (rrule?.isNotEmpty != true) {
      return null;
    }
    rruleUtil.RecurrenceRule? parseRule;
    var hasFREQ = rrule?.contains("FREQ") == true;
    try {
      var replaceFirst = rrule?.replaceFirst("WKST=SU", "WKST=MO") ?? "";
      if (!hasFREQ) {
        replaceFirst += ";FREQ=${rruleUtil.Frequency.yearly}";
      }
      parseRule = rruleUtil.RecurrenceRule.fromString("RRULE:${replaceFirst}");
    } catch (e) {
      ALogger.e(rrule);
      ALogger.e(e);
    }
    if (parseRule == null) {
      return null;
    }
    return RecurrenceRule(
        transformEventFrequency(hasFREQ ? parseRule.frequency : null),
        interval: 1);
    // return RecurrenceRule(transformEventFrequency(parseRule.frequency),
    //     totalOccurrences: parseRule.count,
    //     interval: parseRule.interval,
    //     endDate: parseRule.until,
    //     daysOfWeek: parseRule.hasByWeekDays
    //         ? parseRule.byWeekDays.map((e) => DayOfWeek.values[e.day]).toList()
    //         : null,
    //     dayOfMonth:
    //         parseRule.hasByMonthDays ? parseRule.byMonthDays.first : null,
    //     monthOfYear: parseRule.hasByMonths
    //         ? MonthOfYear.values[parseRule.byMonths.first]
    //         : null,
    //     weekOfMonth: parseRule.hasByWeeks
    //         ? WeekNumber.values[parseRule.byWeeks.first]
    //         : null);
  }

  @override
  bool operator ==(Object other) {
    if (identical(this, other)) return true;
    return other is EventDTO && (other.id == id || other.event_id == event_id);
  }

  @override
  int get hashCode {
    return id.hashCode + event_id.hashCode;
  }

  refreshETag() {
    etag = DateTime.now().millisecondsSinceEpoch;
  }

  markAsSynchronized() {
    sync = 1;
    refreshETag();
  }

  setupFotocubeCalendarType() {
    accountType = ACCOUNT_TYPE;
    accountName = UserManager.instance.getEmail();
    calendarDisplayName = fotocubeCalendarDisplayName();
  }

  @override
  String toString() {
    return 'EventDTO{autoid : $autoId,frame_id: $frame_id, id: $id, event_id: $event_id, title: $title, accountName: $accountName accountType: $accountType calendarDisplayName: $calendarDisplayName dtstart: $dtstart, attendees:$attendees, rrule ：$rrule}';
  }
}

/// {interval: 1, endDate: 1726847999000, recurrenceFrequency: 1, daysOfWeek: [5]},
/// {interval: 1, endDate: 1726847999000, recurrenceFrequency: 2, dayOfMonth: 26}
/// {totalOccurrences: 5, interval: 1, recurrenceFrequency: 3, daysOfWeek: [5], monthOfYear: 7, weekOfMonth: 4}
/// {calendarId: 4, eventId: 393, eventTitle: 周循环, eventDescription: , eventStartDate: 1722261600000, eventStartTimeZone: Asia/Shanghai, eventEndDate: 1722265200000, eventEndTimeZone: Asia/Shanghai, eventAllDay: false, eventLocation: , eventURL: null, availability: BUSY, eventStatus: CONFIRMED, attendees: [], organizer: null, recurrenceRule: {interval: 1, endDate: 1724860799000, recurrenceFrequency: 1, daysOfWeek: [1, 5]}, reminders: [{minutes: 10}]}
///{calendarId: 4, eventId: 394, eventTitle: 月某天, eventDescription: , eventStartDate: 1722006000000, eventStartTimeZone: Asia/Shanghai, eventEndDate: 1722009600000, eventEndTimeZone: Asia/Shanghai, eventAllDay: false, eventLocation: , eventURL: null, availability: BUSY, eventStatus: CONFIRMED, attendees: [], organizer: null, recurrenceRule: {interval: 1, endDate: 1754755199000, recurrenceFrequency: 2, dayOfMonth: 26}, reminders: [{minutes: 10}]}
parseRecurrenceRule(Event e) {
  RecurrenceRule? rule = e.recurrenceRule;
  if (rule == null || rule.recurrenceFrequency == null) return null;
  try {
    var recurrenceRule = rruleUtil.RecurrenceRule(
      frequency: transformToFrequency(rule.recurrenceFrequency!),
      until: rule.endDate?.toUtc(),
      byWeekDays: rule.daysOfWeek
              ?.map((e) => rruleUtil.ByWeekDayEntry(e.value))
              .toList() ??
          [],
      byMonthDays: rule.dayOfMonth != null ? [rule.dayOfMonth!] : [],
      byWeeks: rule.weekOfMonth?.value != null ? [rule.weekOfMonth!.value] : [],
      byMonths:
          rule.monthOfYear?.value != null ? [rule.monthOfYear!.value] : [],
      count: rule.totalOccurrences,
      interval: rule.interval,
    );
    // var ruleStr = recurrenceRule.toString();
    // var res = ruleStr.substring("RRULE:".length, ruleStr.length);
    // // print("recurrenceRule.toString  : ${res}");
    // return res;
    return recurrenceRule;
  } catch (e) {
    print(e);
  }
  return null;
}

transformToFrequency(RecurrenceFrequency recurrenceFrequency) {
  rruleUtil.Frequency? frequency;
  switch (recurrenceFrequency) {
    case RecurrenceFrequency.Daily:
      frequency = rruleUtil.Frequency.daily;
      break;
    case RecurrenceFrequency.Weekly:
      frequency = rruleUtil.Frequency.weekly;
      break;
    case RecurrenceFrequency.Monthly:
      frequency = rruleUtil.Frequency.monthly;
      break;
    case RecurrenceFrequency.Yearly:
      frequency = rruleUtil.Frequency.yearly;
      break;
    default:
      null;
  }
  return frequency;
}

transformEventFrequency(rruleUtil.Frequency? recurrenceFrequency) {
  RecurrenceFrequency? frequency;
  switch (recurrenceFrequency) {
    case rruleUtil.Frequency.daily:
      frequency = RecurrenceFrequency.Daily;
      break;
    case rruleUtil.Frequency.weekly:
      frequency = RecurrenceFrequency.Weekly;
      break;
    case rruleUtil.Frequency.monthly:
      frequency = RecurrenceFrequency.Monthly;
      break;
    case rruleUtil.Frequency.yearly:
      frequency = RecurrenceFrequency.Yearly;
      break;
    default:
      null;
  }
  return frequency;
}

fotocubeCalendarDisplayName() => "${UserManager.instance.getEmail()}_cal";

const ACCOUNT_TYPE = "fotocube.com";

extension calendarExtensions on Calendar {
  String fixAccountType() {
    return accountType?.toLowerCase() ?? "";
  }

  String fixAccountName() {
    return accountName?.toLowerCase() ?? "";
  }

  String fixDisplayName() {
    return name?.toLowerCase() ?? "";
  }

  bool isGoogle() {
    return fixAccountType().contains("google") ||
        fixAccountName().contains("google");
  }

  bool isOutlook() {
    return fixAccountType().contains("outlook") ||
        fixAccountName().contains("outlook");
  }

  bool isICloud() {
    return fixAccountType().contains("icloud") ||
        fixAccountName().contains("icloud");
  }

  bool isFotocube() {
    return fixDisplayName() == fotocubeCalendarDisplayName();
  }
}

extension eventDTOExtensions on EventDTO {
  bool isGoogle() {
    return fixAccountType().contains("google") ||
        fixAccountName().contains("google");
  }

  bool isOutlook() {
    return fixAccountType().contains("outloook") ||
        fixAccountName().contains("outloook");
  }

  bool isICloud() {
    return fixAccountType().contains("icloud") ||
        fixAccountName().contains("icloud");
  }

  bool isFotocube() {
    return accountType == ACCOUNT_TYPE;
  }

  String fixAccountType() {
    return accountType?.toLowerCase() ?? "";
  }

  String fixAccountName() {
    return accountName?.toLowerCase() ?? "";
  }

  String fixDisplayName() {
    return calendarDisplayName?.toLowerCase() ?? "";
  }
}
